home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Resources / Online / Term / Extras / Source / gtlayout-source.lha / gtlayout_lib.c < prev    next >
C/C++ Source or Header  |  1996-10-11  |  21KB  |  634 lines

  1. /*
  2. **    GadTools layout toolkit
  3. **
  4. **    Copyright © 1993-1996 by Olaf `Olsen' Barthel
  5. **        Freely distributable.
  6. **
  7. **    :ts=4
  8. */
  9.  
  10. #ifndef _GTLAYOUT_GLOBAL_H
  11. #include "gtlayout_global.h"
  12. #endif
  13.  
  14. /****** gtlayout.library/--version-- ******************************************
  15. *
  16. *   NOTES
  17. *    This document describes gtlayout.library v5.12 or higher. Do not assume that
  18. *    previous library releases support the same features.
  19. *
  20. ******************************************************************************
  21. *
  22. */
  23.  
  24. /****** gtlayout.library/--background-- ******************************************
  25. *
  26. *   NOTES
  27. *    1. General information
  28. *
  29. *    1.1 Purpose
  30. *
  31. *    The GUI code included in this archive helps to create user interfaces
  32. *    using gadtools.library with a minimum of effort. The code
  33. *    automatically takes care of the font to be used, making the user
  34. *    interface font independent. Localizing support is built right into
  35. *    the code, just install a callback hook and pass numeric IDs for the
  36. *    gadget labels: the code will invoke your hook in order to get the
  37. *    text required. Keystroke activation of gadgets is also taken care
  38. *    of, in fact the code will -- unless told not to do so -- assign keyboard
  39. *    shortcuts to the gadgets created all on its own. Every effort has been
  40. *    made to make the code reentrant, so it can be put into a shared library.
  41. *    If a user interface does not fit onto a screen provisions are made to
  42. *    choose a smaller font and to rescale the window contents until they fit.
  43. *    Last but not least the user interface code offers transparent extensions
  44. *    to the standard gadtools.library objects, such as LISTVIEW_KIND objects
  45. *    which respond to double-clicks or STRING_KIND objects which can be used
  46. *    to enter password text as they will not display the characters entered.
  47. *
  48. *
  49. *    1.2 Distribution
  50. *
  51. *    The code is *free*, you don't need to pay any money to use it, nor
  52. *    do you need to quote my name in the documentation, the program or
  53. *    anywhere else. You are allowed to make changes to the code, but if
  54. *    you stumble across any bugs or even know how to fix them, please
  55. *    let me know. It does not matter whether you intend to sell a program
  56. *    to use the code, use the code in shareware, gift-ware, freeware or
  57. *    etc.-ware programs: the code still remains royalty-free.
  58. *
  59. *
  60. *    1.3 Caveats
  61. *
  62. *    The code is pretty large, about 80K-100K bytes in size. Not all
  63. *    gadtools.library type objects are supported, notably
  64. *    GENERIC_KIND objects. The code is not as flexible as
  65. *    gadtools.library, so certain things which are easily done using
  66. *    gadtools.library may be pretty difficult or even impossible.
  67. *    The code is written entirely in `C' and requires SAS/C to
  68. *    compile. Some parts of the code are highly recursive; I haven't
  69. *    tested how much stack they might require in certain cases,
  70. *    but I recommend that you don't overuse the grouping feature.
  71. *    The data structures required to create and maintain the
  72. *    user interface are huge, a single window might require more
  73. *    than 4K-6K of memory. Proportional font support only works
  74. *    well starting with Kickstart v39 and up, v2.04 will probably
  75. *    not look quite that pretty.
  76. *
  77. *
  78. *    2. Programming
  79. *
  80. *    2.1 Client libraries required for link library version
  81. *
  82. *    You need to have SysBase and GadToolsBase initialized in order to make
  83. *    use of the code, i.e. your code has to do
  84. *    WaitPort()...GT_GetIMsg()...GT_ReplyIMsg all on its own. The code makes
  85. *    use of the memory pools introduced in exec.library v39, but calls the
  86. *    equivalent routines in amiga.lib. Note: as of this writing the pools
  87. *    code in amiga.lib v40.14 is broken, so you need to link with Mike
  88. *    Sinz' fixed pools.lib.
  89. *
  90. *
  91. *    2.2 Invocation procedure
  92. *
  93. *    The typical invocation procedure looks roughly like this:
  94. *
  95. *       LT_Init();    // only for link library version
  96. *       :
  97. *       :
  98. *          LT_CreateHandleTags();
  99. *             LT_New();
  100. *             :
  101. *             :
  102. *             LT_New();
  103. *                LT_Build();
  104. *                   LT_HandleInput();
  105. *          LT_DeleteHandle();
  106. *       :
  107. *       :
  108. *       LT_Exit();    // only for link library version
  109. *
  110. *    You need to call LT_Init() only once in your program, it will initialize
  111. *    the libraries and global data structures required by the user interface
  112. *    code. When you are finished with the user interface and your program is
  113. *    about to exit you need to call LT_Exit() or memory will get lost.
  114. *    Note that LT_Init() is not protected against multiple invocations. If
  115. *    called repeatedly memory will get lost which can never be reclaimed.
  116. *    However, LT_Exit() is protected against multiple invocations, you can
  117. *    also call it before ever giving LT_Init() a call, but I doubt this
  118. *    would make much sense. If you are using the shared gtlayout.library
  119. *    no call to LT_Init()/LT_Exit() is necessary as these calls are already
  120. *    wrapped into the library opening code.
  121. *       Before you can actually start building a window layout a call to
  122. *    LT_CreateHandleTags() needs to be made. You need to pass in a pointer
  123. *    to the Screen your user interface window is to be opened on and,
  124. *    optionally, a few tags to control the look and performance of the
  125. *    interface. *Never* close the screen in question before calling
  126. *    LT_DeleteHandle() or nasty things will happen. For public screens
  127. *    the code will try to lock the screen in question. With the handle
  128. *    LT_CreateHandleTags() returned you can call LT_New() to build the
  129. *    user interface. When finished a call to LT_Build() will finally
  130. *    open a window and place the gadgets inside. A pointer to the
  131. *    Window created will be returned, ready to be used for the
  132. *    WaitPort()...GT_GetIMsg()...LT_HandleInput()...GT_ReplyIMsg()
  133. *    loop. When finished, a call to LT_DeleteHandle() will close the
  134. *    window and release all the memory associated with it. The design
  135. *    of the interface code is similar to the corresponding calls in
  136. *    gadtools.library, i.e. you don't need to worry about LT_New()
  137. *    failing to allocate memory for the objects required. When it comes
  138. *    to LT_Build() the code will know about any trouble which would
  139. *    show up during previous invocations of LT_New(). In essence,
  140. *    if LT_Build() returns NULL something is wrong.
  141. *
  142. *
  143. *    2.3 Hierarchic grouping
  144. *
  145. *    The basic building block of the user interface is a group, either
  146. *    a horizontal or a vertical group. Adding gadgets or other objects
  147. *    to a horizontal group will place them side by side from left to
  148. *    right. A vertical group causes objects to be place from top to
  149. *    bottom in one straight line. Groups help to arrange objects
  150. *    neatly stacked, centered and properly aligned with other
  151. *    members of the group.
  152. *
  153. *    MUCHO IMPORTANTE: there is a bug lurking in the code which I never
  154. *    had the luck to find and fix. One would expect to create
  155. *    user interface structures like this:
  156. *
  157. *       <group start>
  158. *          <button>
  159. *          <list>
  160. *          <group start>
  161. *             <slider>
  162. *             <text>
  163. *          <group end>
  164. *          <button>
  165. *       <group end>
  166. *
  167. *    However, it is in fact not possible to mix gadgets and groups.
  168. *    Thus, the user interface structure would have to look like this:
  169. *
  170. *       <group start>
  171. *          <group start>
  172. *             <button>
  173. *             <list>
  174. *          <group end>
  175. *          <group start>
  176. *             <slider>
  177. *             <text>
  178. *          <group end>
  179. *          <group start>
  180. *             <button>
  181. *          <group end>
  182. *       <group end>
  183. *
  184. *    Or in other words: groups only mix with other groups.
  185. *
  186. *    You build groups using three different object types. In this
  187. *    context `object type' refers to a specific numeric value the
  188. *    LT_New() routine knows which will cause it to add another leaf
  189. *    to the user interface structure tree. Here is an example:
  190. *
  191. *       struct LayoutHandle *Handle;
  192. *
  193. *       if(Handle = LT_CreateHandleTags(NULL,
  194. *          LAHN_AutoActivate,FALSE,
  195. *       TAG_DONE))
  196. *       {
  197. *          struct Window *Window;
  198. *
  199. *          LT_New(Handle,
  200. *             LA_Type,      VERTICAL_KIND,  \* A vertical group. *\
  201. *             LA_LabelText, "Main group",   \* Group title text. *\
  202. *          TAG_DONE);
  203. *          {
  204. *             LT_New(Handle,
  205. *                LA_Type,      BUTTON_KIND, \* A plain button. *\
  206. *                LA_LabelText, "A button",
  207. *                LA_ID,        11,
  208. *             TAG_DONE);
  209. *
  210. *             LT_New(Handle,
  211. *                LA_Type,      XBAR_KIND,   \* A separator bar. *\
  212. *             TAG_DONE);
  213. *
  214. *             LT_New(Handle,
  215. *                LA_Type,      BUTTON_KIND, \* A plain button. *\
  216. *                LA_LabelText, "Another button",
  217. *                LA_ID,        22,
  218. *             TAG_DONE);
  219. *
  220. *             LT_New(Handle,
  221. *                LA_Type,      END_KIND,    \* This ends the current group. *\
  222. *             TAG_DONE);
  223. *          }
  224. *
  225. *          if(Window = LT_Build(Handle,
  226. *            LAWN_Title,     "Window title",
  227. *            LAWN_IDCMP,     IDCMP_CLOSEWINDOW,
  228. *            WA_CloseGadget, TRUE,
  229. *          TAG_DONE))
  230. *          {
  231. *              struct IntuiMessage *Message;
  232. *              ULONG                MsgQualifier,
  233. *                                   MsgClass;
  234. *              UWORD                MsgCode;
  235. *              struct Gadget       *MsgGadget;
  236. *              BOOL                 Done = FALSE;
  237. *
  238. *              do
  239. *              {
  240. *                  WaitPort(Window->UserPort);
  241. *
  242. *                  while(Message = GT_GetIMsg(Window->UserPort))
  243. *                  {
  244. *                     MsgClass     = Message->Class;
  245. *                     MsgCode      = Message->Code;
  246. *                     MsgQualifier = Message->Qualifier;
  247. *                     MsgGadget    = Message->IAddress;
  248. *
  249. *                     GT_ReplyIMsg(Message);
  250. *
  251. *                     LT_HandleInput(Handle,MsgQualifier,&MsgClass,
  252. *                         &MsgCode,&MsgGadget);
  253. *
  254. *                     switch(MsgClass)
  255. *                     {
  256. *                        case IDCMP_CLOSEWINDOW:
  257. *
  258. *                            Done = TRUE;
  259. *                            break;
  260. *
  261. *                        case IDCMP_GADGETUP:
  262. *
  263. *                            switch(MsgGadget->GadgetID)
  264. *                            {
  265. *                                case 11: printf("First gadget\n");
  266. *                                         break;
  267. *
  268. *                                case 22: printf("Second gadget\n");
  269. *                                         break;
  270. *                            }
  271. *
  272. *                            break;
  273. *                     }
  274. *                  }
  275. *              }
  276. *              while(!Done);
  277. *          }
  278. *
  279. *          LT_DeleteHandle(Handle);
  280. *       }
  281. *
  282. *    The example creates one single group, places a few objects inside,
  283. *    calls the layout routine, handles the input and finally cleans
  284. *    things up again. This example also shows that you *need* at
  285. *    least one group in your tree (to form the root) in order to get
  286. *    things to work.
  287. *       The input loop requires you to call LT_HandleInput() in order
  288. *    to get the user interface code to filter out certain events and
  289. *    to update internal information. The data passed in must have
  290. *    been processed via the gadtools.library routines. You *must not*
  291. *    call LT_HandleInput() before GT_ReplyIMsg() is called since the
  292. *    routine may call intuition.library and gadtools.library routines
  293. *    which in turn might lead to a system lock-up if the message
  294. *    has not been processed yet. The first thing to do after LT_HandleInput()
  295. *    has done whatever was necessary to the data you passed in is
  296. *    examine the MsgClass variable. The user interface code will
  297. *    `fake' certain message events using the variables passed in,
  298. *    *do not* use any other data gathered from the original
  299. *    IntuiMessage. The MsgClass may include event types you did
  300. *    not ask for, i.e. the IDCMP flags of the window opened
  301. *    will be set according to the objects you added to the window.
  302. *    Also, the IDCMP_IDCMPUPDATE message class will show up for
  303. *    certain objects. More on this later in this document.
  304. *
  305. *
  306. *    2.4 Setting and getting object attributes
  307. *
  308. *    The mechanism to update and query object attributes does not
  309. *    exactly match the familiar gadtools.library interface. In
  310. *    fact, the routine to change gadget attributes will forward
  311. *    the tagitem list passed in to gadtools.library/GT_SetGadgetAttrs().
  312. *    On the other hand the routine to query object attributes does
  313. *    not work like gadtools.library/GT_GetGadgetAttrs(). The
  314. *    user interface code assumes that all objects it can handle and
  315. *    create posess certain attributes unique to the type of the
  316. *    object in question. For example, the unique attribute of a
  317. *    STRING_KIND object would be a pointer to the string it
  318. *    `contains'. The unique attribute of a SLIDER_KIND object is
  319. *    the current slider position. The LT_GetAttributes() routine
  320. *    will return this attribute, but also accept a tagitem list
  321. *    to fill in for certain special tag values.
  322. *
  323. *
  324. *    2.5 Extra data
  325. *
  326. *    Once a LayoutHandle has been created the interface code will
  327. *    provide you with a number of information concerning the screen
  328. *    the handle has been attached to. This information includes
  329. *    the DrawInfo structure of the screen, the VisualInfo data
  330. *    and the Screen address. This information is read-only.
  331. *
  332. *
  333. *    2.6 Menus
  334. *
  335. *    With a LayoutHandle available a routine called LT_LayoutMenuTags()
  336. *    will create a standard Intuition menu structure via gadtools.library
  337. *    which can be passed to LT_Build(). Note that this
  338. *    routine does not modify any data passed in, it does neither
  339. *    attach the menu created to the LayoutHandle passed in,
  340. *    nor does it change the NewMenu table.
  341. *
  342. *
  343. *    2.7 Localization
  344. *
  345. *    All object and menu creation routines support localization via
  346. *    a Hook callback interface, i.e. you can pass a pointer to an
  347. *    initialized Hook structure to LT_CreateHandleTags() which will
  348. *    later be used to supply label and list text for objects
  349. *    created. The Hook callback routine is called in the following
  350. *    fashion:
  351. *
  352. *       String = HookFunc(struct Hook *Hook,struct LayoutHandle *Handle,LONG ID)
  353. *         D0                            A0                         A2        A1
  354. *
  355. *    Or in other words: a locale string ID is passed in, the routine is supposed
  356. *    to look up the string to match this ID and to return it.
  357. *
  358. *
  359. *    2.8 Object types to generate IDCMP_IDCMPUPDATE events
  360. *
  361. *    Certain objects convey extra information which is merged into the `fake'
  362. *    input stream passed to the client calling LT_HandleInput(). These objects
  363. *    are:
  364. *
  365. *       STRING_KIND
  366. *       TEXT_KIND
  367. *       PALETTE_KIND
  368. *
  369. *          The user pressed the `select' button which belongs
  370. *          to this gadget. The MsgGadget pointer indicates the
  371. *          STRING_KIND/TEXT_KIND/PALETTE_KIND object the `select'
  372. *          button belongs to.
  373. *
  374. *       LISTVIEW_KIND
  375. *
  376. *          The user double-clicked on an entry. The entry number
  377. *          is returned in the MsgCode variable. The MsgGadget
  378. *          pointer indicates the LISTVIEW_KIND object the user
  379. *          has clicked on.
  380. *
  381. *
  382. *    2.9 Keystroke activation
  383. *
  384. *    Unless forbidden via the the LA_NoKey tag item the user interface
  385. *    code will pick the keyboard shortcuts for all gadgets on its own.
  386. *    The currently active global console keymap will be checked at the
  387. *    time when LT_Init() is called in order to make sure subsequent
  388. *    calls to LT_Build() will use only keys the user can press on
  389. *    the keyboard. Double-dead keys are also excluded from the
  390. *    table created. This avoids problems with gadget labels such as
  391. *    "éééé" which would require the user to hit two keys in a row to
  392. *    activate the gadget.
  393. *       If the window created happens to feature a close gadget
  394. *    pressing the `Esc' key will cause the client to receive
  395. *    an IDCMP_CLOSEWINDOW event.
  396. *       A single LISTVIEW_KIND object may receive special treatment
  397. *    if the LALV_CursorKey tag is used: the user will be able to
  398. *    operate the listview using the cursor keys. Note: this
  399. *    will also keep the user interface code from choosing a
  400. *    special keystroke from the gadget label.
  401. *       The user will be able to operate a single BUTTON_KIND
  402. *    object using the return key if the LABT_ReturnKey tag is
  403. *    used. A recessed frame will be drawn around the button hit
  404. *    box to indicate its special status.
  405. *       Pressing the Tab key can be bound to operate a cycle or
  406. *    mx kind object.
  407. *
  408. *    3. Credits
  409. *
  410. *    The original design is based upon the user interface layout code used by
  411. *    `term' 3.1. I put the first version of the layout routines together back
  412. *    in Summer 1993 when I wanted to write the follow-up to `term' v3.4.
  413. *
  414. *    Martin Taillefer rewrote large parts of the code, added new routines and
  415. *    generally improved the performance of the layout process. I owe Martin
  416. *    much for the ideas he put into the library.
  417. *
  418. *    Kai Iske, Christoph Feck, Stefan Becker, Michael Barsoom and Sven Stullich
  419. *    helped to iron out the remaining bugs and piled up bug reports and
  420. *    enhancement requests.
  421. *
  422. ******************************************************************************
  423. *
  424. */
  425.  
  426.  
  427. /*****************************************************************************/
  428.  
  429.  
  430. struct GTLayoutBase
  431. {
  432.     struct Library             LibNode;
  433.  
  434.     struct ExecBase            *ExecBase;
  435.     BPTR                     LibSegment;
  436.     struct SignalSemaphore     LockSemaphore;
  437. };
  438.  
  439. #define SysBase GTLayoutBase->ExecBase
  440.  
  441.  
  442. /*****************************************************************************/
  443.  
  444.  
  445. STATIC APTR LibVectors[] =
  446. {
  447.     LibOpen,
  448.     LibClose,
  449.     LibExpunge,
  450.     LibNull,
  451.  
  452.     LT_LevelWidth,
  453.     LT_DeleteHandle,
  454.     LT_CreateHandle,
  455.     LT_CreateHandleTagList,
  456.     LT_Rebuild,
  457.     LT_HandleInput,
  458.     LT_BeginRefresh,
  459.     LT_EndRefresh,
  460.     LT_GetAttributesA,
  461.     LT_SetAttributesA,
  462.     LT_AddA,
  463.     LT_NewA,
  464.     LT_EndGroup,
  465.     LT_LayoutA,
  466.     LT_LayoutMenusA,
  467.     LibNull,    /* There used to be a FRACTION_KIND support routine here. */
  468.     LibNull,    /* There used to be a FRACTION_KIND support routine here. */
  469.     LibNull,    /* There used to be a FRACTION_KIND support routine here. */
  470.     LT_LabelWidth,
  471.     LT_LabelChars,
  472.     LT_LockWindow,
  473.     LT_UnlockWindow,
  474.     LT_DeleteWindowLock,
  475.     LT_ShowWindow,
  476.     LT_Activate,
  477.     LT_PressButton,
  478.     LT_GetCode,
  479.     LT_GetIMsg,
  480.     LT_ReplyIMsg,
  481.     LT_BuildA,
  482.     LT_RebuildTagList,
  483.     LT_UpdateStrings,
  484.  
  485. #ifdef DO_MENUS
  486.     LT_DisposeMenu,
  487.     LT_NewMenuTemplate,
  488.     LT_NewMenuTagList,
  489.     LT_MenuControlTagList,
  490.     LT_GetMenuItem,
  491.     LT_FindMenuCommand,
  492. #else
  493.     LibNull,
  494.     LibNull,
  495.     LibNull,
  496.     LibNull,
  497.     LibNull,
  498.     LibNull,
  499. #endif    // DO_MENUS
  500.  
  501.     LT_NewLevelWidth,
  502.     LT_Refresh,
  503.     LT_CatchUpRefresh,
  504.  
  505.     (APTR)-1
  506. };
  507.  
  508. struct { ULONG DataSize; APTR Table; APTR Data; struct Library * (*Init)(); } LibInitTab =
  509. {
  510.     sizeof(struct GTLayoutBase),
  511.     LibVectors,
  512.     NULL,
  513.     LibInit
  514. };
  515.  
  516.  
  517. /*****************************************************************************/
  518.  
  519.  
  520. struct Library * LIBENT
  521. LibInit(REG(a0) BPTR Segment,REG(d0) struct GTLayoutBase *GTLayoutBase,REG(a6) struct ExecBase *ExecBase)
  522. {
  523.     extern ULONG __far LibRevision;
  524.  
  525. #ifndef CPU_ANY
  526.     if(ExecBase->LibNode.lib_Version < 37 || !(ExecBase->AttnFlags & AFF_68020))
  527.         return(NULL);
  528. #else
  529.     if(ExecBase->LibNode.lib_Version < 37)
  530.         return(NULL);
  531. #endif    // CPU_ANY
  532.  
  533.     GTLayoutBase->LibNode.lib_Revision = (UWORD)&LibRevision;
  534.  
  535.     GTLayoutBase->LibSegment    = Segment;
  536.     GTLayoutBase->ExecBase        = ExecBase;
  537.  
  538.     InitSemaphore(>LayoutBase->LockSemaphore);
  539.  
  540.     return(GTLayoutBase);
  541. }
  542.  
  543.  
  544. /*****************************************************************************/
  545.  
  546.  
  547. struct Library * LIBENT
  548. LibOpen(REG(a6) struct GTLayoutBase *GTLayoutBase)
  549. {
  550.     struct SignalSemaphore *Semaphore;
  551.  
  552.     GTLayoutBase->LibNode.lib_OpenCnt++;
  553.  
  554.     GTLayoutBase->LibNode.lib_Flags &= ~LIBF_DELEXP;
  555.  
  556.     Semaphore = >LayoutBase->LockSemaphore;
  557.  
  558.     ObtainSemaphore(Semaphore);
  559.  
  560.     if(GTLayoutBase->LibNode.lib_OpenCnt == 1)
  561.     {
  562.         if(!LT_Init())
  563.         {
  564.             LT_Exit();
  565.  
  566.             GTLayoutBase->LibNode.lib_OpenCnt--;
  567.  
  568.             GTLayoutBase = NULL;
  569.         }
  570.     }
  571.  
  572.     ReleaseSemaphore(Semaphore);
  573.  
  574.     return(GTLayoutBase);
  575. }
  576.  
  577.  
  578. /*****************************************************************************/
  579.  
  580.  
  581. BPTR LIBENT
  582. LibExpunge(REG(a6) struct GTLayoutBase *GTLayoutBase)
  583. {
  584.     if(GTLayoutBase->LibNode.lib_OpenCnt == 0 && GTLayoutBase->LibSegment != NULL)
  585.     {
  586.         BPTR TempSegment = GTLayoutBase->LibSegment;
  587.  
  588.         Remove((struct Node *)GTLayoutBase);
  589.  
  590.         FreeMem((BYTE *)GTLayoutBase - GTLayoutBase->LibNode.lib_NegSize,GTLayoutBase->LibNode.lib_NegSize + GTLayoutBase->LibNode.lib_PosSize);
  591.  
  592.         return(TempSegment);
  593.     }
  594.     else
  595.     {
  596.         GTLayoutBase->LibNode.lib_Flags |= LIBF_DELEXP;
  597.  
  598.         return(NULL);
  599.     }
  600. }
  601.  
  602.  
  603. /*****************************************************************************/
  604.  
  605.  
  606. BPTR LIBENT
  607. LibClose(REG(a6) struct GTLayoutBase *GTLayoutBase)
  608. {
  609.     ObtainSemaphore(>LayoutBase->LockSemaphore);
  610.  
  611.     if(GTLayoutBase->LibNode.lib_OpenCnt > 0)
  612.     {
  613.         if(!(--GTLayoutBase->LibNode.lib_OpenCnt))
  614.             LT_Exit();
  615.     }
  616.  
  617.     ReleaseSemaphore(>LayoutBase->LockSemaphore);
  618.  
  619.     if(GTLayoutBase->LibNode.lib_OpenCnt == 0 && (GTLayoutBase->LibNode.lib_Flags & LIBF_DELEXP))
  620.         return(LibExpunge(GTLayoutBase));
  621.     else
  622.         return(NULL);
  623. }
  624.  
  625.  
  626. /*****************************************************************************/
  627.  
  628.  
  629. LONG
  630. LibNull()
  631. {
  632.     return(NULL);
  633. }
  634.